package com.redstars.generate.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.NamingCase;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.redstars.generate.config.GenDataSource;
import com.redstars.generate.convert.SysMainSubTableConvert;
import com.redstars.generate.convert.SysTableFieldConvert;
import com.redstars.generate.entity.SysMainSubTable;
import com.redstars.generate.entity.SysTable;
import com.redstars.generate.entity.SysTableField;
import com.redstars.generate.enums.GeneratorTypeEnum;
import com.redstars.generate.exception.RedstarsException;
import com.redstars.generate.page.PageResult;
import com.redstars.generate.query.SysMainSubTableQuery;
import com.redstars.generate.service.*;
import com.redstars.generate.utils.GenUtils;
import com.redstars.generate.utils.PageUtils;
import com.redstars.generate.vo.SysMainSubTableVo;
import com.redstars.generate.vo.SysProjectConfigVo;
import com.redstars.generate.vo.SysTableFieldVo;
import lombok.AllArgsConstructor;
import com.redstars.generate.convert.SysTableConvert;
import com.redstars.generate.query.SysTableQuery;
import com.redstars.generate.vo.SysTableVo;
import com.redstars.generate.dao.SysTableDao;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import cn.hutool.core.util.ObjectUtil;

/**
 * 代码生成表
 *
 * @author zhouhx 
 * @since 1.0.0 2022-10-05
 */
@Service
@AllArgsConstructor
public class SysTableServiceImpl extends ServiceImpl<SysTableDao, SysTable> implements SysTableService {
    private final SysDatasourceService dataSourceService;
    private final SysTableFieldService tableFieldService;
    private final SysProjectConfigService configService;
    private final SysMainSubTableService mainSubTableService;

    @Override
    public PageResult<SysTableVo> page(SysTableQuery query) {
        LambdaQueryWrapper<SysTable> wrapper = getWrapper(query);
        PageUtils<SysTable> pageUtils = new PageUtils<>();
        IPage<SysTable> page = this.page(pageUtils.getPage(query), wrapper);

        return pageUtils.getPageData(page,SysTableVo.class);
    }

    private LambdaQueryWrapper<SysTable> getWrapper(SysTableQuery query){
        LambdaQueryWrapper<SysTable> wrapper = Wrappers.lambdaQuery();
        if(StrUtil.isNotBlank(query.getTableName())){
            wrapper.like(SysTable::getTableName,query.getTableName());
        }
        return wrapper;
    }

    @Override
    public void save(SysTableVo vo) {
        SysTable entity = SysTableConvert.INSTANCE.convert(vo);

        int insert = baseMapper.insert(entity);
        if(insert>0){
            vo.setId(entity.getId());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(SysTableVo vo) {
        SysTable entity = SysTableConvert.INSTANCE.convert(vo);

        updateById(entity);

        //子表
        if(CollUtil.isNotEmpty(vo.getSubTableList())){
            vo.getSubTableList().forEach(subTableVo ->{
                Long id = subTableVo.getId();
                if(ObjectUtil.isNotEmpty(id)){
                    mainSubTableService.update(subTableVo);
                }else{
                    mainSubTableService.save(subTableVo);
                }
            });
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(List<Long> idList) {
        // 删除表
        this.baseMapper.deleteBatchIds(idList);

        // 删除列
        tableFieldService.deleteBatchTableIds(idList);
    }
    @Override
    public SysTableVo detail(Long id) {
        SysTable detail = this.getById(id);
        if (ObjectUtil.isEmpty(detail)) {
        throw new RedstarsException("记录不存在");
        }
        SysTableVo sysTableVo = SysTableConvert.INSTANCE.convert(detail);
        List<SysTableFieldVo> tableIdList= tableFieldService.getByTableId(detail.getId());
        sysTableVo.setFieldList(tableIdList);
        //子表
        SysMainSubTableQuery query = new SysMainSubTableQuery();
        query.setMainTableId(id);

        List<SysMainSubTableVo> mainSubTables = mainSubTableService.list(query);
        sysTableVo.setSubTableList(mainSubTables);
        return sysTableVo;
    }

    @Override
    public void sync(Long id) {
        SysTable table = this.getById(id);

        // 初始化配置信息
        GenDataSource datasource = dataSourceService.get(table.getDatasourceId());

        // 从数据库获取表字段列表
        List<SysTableField> dbTableFieldList = GenUtils.getTableFieldList(datasource, table.getId(), table.getTableName());
        if (dbTableFieldList.size() == 0) {
            throw new RedstarsException("同步失败，请检查数据库表：" + table.getTableName());
        }

        List<String> dbTableFieldNameList = dbTableFieldList.stream().map(SysTableField::getFieldName).collect(Collectors.toList());

        // 表字段列表
        List<SysTableFieldVo> tableFieldList = tableFieldService.getByTableId(id);

        Map<String, SysTableFieldVo> tableFieldMap = tableFieldList.stream().collect(Collectors.toMap(SysTableFieldVo::getFieldName, Function.identity()));

        // 初始化字段数据
        tableFieldService.initFieldList(dbTableFieldList);

        // 同步表结构字段
        dbTableFieldList.forEach(field -> {
            // 新增字段
            if (!tableFieldMap.containsKey(field.getFieldName())) {
                tableFieldService.save(field);
                return;
            }

            // 修改字段
            SysTableFieldVo updateField = tableFieldMap.get(field.getFieldName());
            updateField.setPrimaryPk(field.getPrimaryPk());
            updateField.setFieldComment(field.getFieldComment());
            updateField.setFieldType(field.getFieldType());
            updateField.setAttrType(field.getAttrType());


            tableFieldService.updateById(SysTableFieldConvert.INSTANCE.convert(updateField));
        });

        // 删除数据库表中没有的字段
        List<SysTableFieldVo> delFieldList = tableFieldList.stream().filter(field -> !dbTableFieldNameList.contains(field.getFieldName())).collect(Collectors.toList());
        if (delFieldList.size() > 0) {
            List<Long> fieldIds = delFieldList.stream().map(SysTableFieldVo::getId).collect(Collectors.toList());
            tableFieldService.removeBatchByIds(fieldIds);
        }

    }

    @Override
    public void tableImport(Long datasourceId, List<String> tableNameList) {
        //获取项目的配置
        SysProjectConfigVo configVo = configService.getDefalut();
        if(ObjectUtil.isEmpty(configVo)){
            configVo = new SysProjectConfigVo();
        }
        for (String tableName : tableNameList) {
            // 初始化配置信息
            GenDataSource dataSource = dataSourceService.get(datasourceId);
            // 查询表是否存在
            SysTableVo table = this.getByTableName(tableName);
            // 表存在
            if (table != null) {
                throw new RedstarsException(tableName + "已存在");
            }

            // 从数据库获取表信息
            table = GenUtils.getTable(dataSource, tableName);

            //读取系统默认的配置包信息
            // 保存表信息
            table.setPackageName(configVo.getPackageName());
            table.setBackendPath(configVo.getBackendPath());
            table.setFrontendPath(configVo.getFrontendPath());
            table.setAuthor(configVo.getAuthor());
            table.setGeneratorType(GeneratorTypeEnum.ZIP_DOWNLOAD.ordinal());
            table.setClassName(NamingCase.toPascalCase(tableName));
            table.setModuleName(configVo.getModuleName());
            table.setFunctionName(GenUtils.getFunctionName(tableName));
            table.setBaseclassId(configVo.getBaseclassId());
            table.setCreateTime(new Date());
            table.setSysProjectId(configVo.getSysProjectId());
            this.save(table);

            // 获取原生字段数据
            List<SysTableField> tableFieldList = GenUtils.getTableFieldList(dataSource, table.getId(), table.getTableName());
            // 初始化字段数据
            tableFieldService.initFieldList(tableFieldList);
            // 批量保存列数据
            tableFieldService.saveBatch(tableFieldList);

            try {
                //释放数据源
                dataSource.getConnection().close();
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
    }

    @Override
    public SysTableVo getByTableName(String tableName) {
        LambdaQueryWrapper<SysTable> queryWrapper = Wrappers.lambdaQuery();
        SysTable sysTable = baseMapper.selectOne(queryWrapper.eq(SysTable::getTableName, tableName));
        return SysTableConvert.INSTANCE.convert(sysTable);
    }

    @Override
    public List<SysTableVo> list(SysTableQuery query) {
        LambdaQueryWrapper<SysTable> wrapper = getWrapper(query);
        wrapper.orderByAsc(SysTable::getCreateTime);
        List<SysTable> list = list(wrapper);

        return SysTableConvert.INSTANCE.convertList(list);
    }

}